package com.bungarus.busi;

import com.bungarus.Busi;
import com.bungarus.codec.protobuf.MessageProtobuf;
import org.apache.log4j.Logger;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;

/**
 * Created by tang on 2018/12/26.
 */
public class ReceiptHunter {
    Logger logger = Logger.getLogger(ReceiptHunter.class);
    private static ReceiptHunter hunter = new ReceiptHunter();
    private ReceiptHunter() {
    }

    public static ReceiptHunter getInstance() {
        return hunter;
    }

    /**
     * To find current online client
     * @param message message the client sent
     * @param busiServer server processing busi logic
     * @return current online client connected to the access node
     */
    public Optional<HunterInfo> locateFirst(MessageProtobuf.Message message, Busi busiServer) {
        //1. find receipt in current cluster first.
        SessionManagement sessionManagement = SessionManagement.getInstance();
        Optional<String> sessionInfo = sessionManagement.retrieve(message.getHeader().getTo(),
                String.valueOf(message.getHeader().getTenantID()),
                message.getHeader().getApp(),
                message.getHeader().getDev());

        HunterInfo result = null;
        if (sessionInfo.isPresent()) {
            //value pattern: {userId},{sessionId},{ipport}
            String[] values = StringUtils.tokenizeToStringArray(sessionInfo.get(), SessionManagement.VALUE_SEPERATOR);
            String reciptId = values[0];
            String sessionId = values[1];
            String ipport = values[2];

            List<InnerClient> accessClients = busiServer.getInnerClientList().get(Busi.CLUSTER_TAG_ACCESS);
            for (InnerClient accessClient : accessClients) {
                if (ipport.equals(accessClient.getSrvIp() + ":" + accessClient.getSrvPort())) {
                    HunterInfo info = new HunterInfo();
                    info.busi2AccessClient = accessClient;
                    info.sessionInAccess = sessionId;

                    result = info;
                    break;
                }
            }
        }
        else {
            //TODO: 2. find receipt in other clusters second if the person cannot be found in step 1.
        }
        return Optional.ofNullable(result);
    }

    /**
     * To find all clients were online.
     * @param message message the current online client sent
     * @param busiServer server processing busi logic
     * @return all clients which match the ip and port cached in session container
     */
    public List<HunterInfo> locateAll(MessageProtobuf.Message message, Busi busiServer) {
        //1. find receipt in current cluster first.
        SessionManagement sessionManagement = SessionManagement.getInstance();
        Set sessionInfos = sessionManagement.retrieve(message.getHeader().getTo(),
                String.valueOf(message.getHeader().getTenantID()));
        logger.debug("==================== result: " + sessionInfos.size());
        List<HunterInfo> result = new ArrayList<>(0);
        List<InnerClient> accessClients = busiServer.getInnerClientList().get(Busi.CLUSTER_TAG_ACCESS);
        if (null != sessionInfos && sessionInfos.size() > 0) {
            sessionInfos.stream().forEach(sessionInfo -> {
                logger.debug("==================== sessionInfo: " + sessionInfo.toString());
                String[] values = StringUtils.tokenizeToStringArray(sessionInfo.toString(), SessionManagement.VALUE_SEPERATOR);
                String reciptId = values[0];
                String sessionId = values[1];
                String ipport = values[2];
                for (int index = accessClients.size()-1; index >=0; index--) {
                    InnerClient accessClient = accessClients.get(index);
                    if (ipport.equals(accessClient.getSrvIp() + ":" + accessClient.getSrvPort())) {
                        HunterInfo info = new HunterInfo();
                        info.sessionInAccess = sessionId;
                        info.busi2AccessClient = accessClient;

                        result.add(info);
                    }
                }
            });
        }
        else {
            //TODO: 2. find receipt in other clusters second if the person cannot be found in step 1.
        }
        logger.debug("==================== result: " + result.size());
        return result;

    }

    public static class HunterInfo {
        public String sessionInAccess;
        public InnerClient busi2AccessClient;
    }
}
